<?php
// $Id: brazilianids.check.inc,v 1.1.2.4 2010/12/27 20:18:35 wasare Exp $

/**
 * @file
 * brazilianids.check.inc
 *
 * Deal with brazilian IDs like CPF and CNPJ.
 */

/**
 * Format the CNPJ number
 *
 * @param &$cnpj
 *   Number, the CNPJ number
 * @return
 *   String, the new CNPJ
 */
function _brazilianids_format_cnpj($cnpj) {
  $cnpj = _brazilianids_clean_cpfcnpj($cnpj);
  return drupal_substr($cnpj, 0, 2) .'.'. drupal_substr($cnpj, 2, 3) .'.'.
    drupal_substr($cnpj, 5, 3) .'-'. drupal_substr($cnpj, 8, 4) .'/'. drupal_substr($cnpj, 12, 2);
}

/**
 * Format the CPF number
 *
 * @param &$cpf
 *   Number, the CPF number
 * @return
 *   String, the new CPF
 */
function _brazilianids_format_cpf($cpf) {
  $cpf = _brazilianids_clean_cpfcnpj($cpf);
  return drupal_substr($cpf, 0, 3) .'.'. drupal_substr($cpf, 3, 3) .'.'.
    drupal_substr($cpf, 6, 3) .'-'. drupal_substr($cpf, 9, 3);
}

/**
 * Format the CPF number
 *
 * @param &$cpf
 *   Number, the CPF number
 * @return
 *   String, the new CPF
 */
function _brazilianids_format_cpfcnpj($cpfcnpj) {
  $cpfcnpj = _brazilianids_clean_cpfcnpj($cpfcnpj);

  if (drupal_strlen($cpfcnpj) == 11) {
    return _brazilianids_format_cpf($cpfcnpj);
  }
  elseif (drupal_strlen($cpfcnpj) == 14) {
    return _brazilianids_format_cnpj($cpfcnpj);
  }
  else {
    return FALSE;
  }
}

/**
 * Return 'CPF' or 'CNPJ' depend of the type of param
 *
 * @param &$cpfcnpj
 *  Number, to determine type
 * @return
 *  String, the string 'CPF' if type of $cpfcnpj is CPF or 'CNPJ' if is a cpnj
 *  number or false if not valid CPF/CNPJ
 */
function _brazilianids_is_cpf_cnpj($cpfcnpj) {
  $cpfcnpj = _brazilianids_clean_cpfcnpj($cpfcnpj);

  $return = $cpfcnpj;

  if (drupal_strlen($cpfcnpj) == 11) {
    $return = _brazilianids_validate_cpf($cpfcnpj);
  }
  elseif (drupal_strlen($cpfcnpj) == 14) {
    $return = _brazilianids_validate_cnpj($cpfcnpj);
  }
  else {
    $return = FALSE;
  }

  if (!$return) return NULL;

  if (drupal_strlen($return) == 11) {
    return 'CPF';
  }
  elseif (drupal_strlen($return) == 14) {
    return 'CNPJ';
  }
  else {
    return NULL;
  }
}

/**
 * Check if the provided CNPJ is valid
 *
 * @param &$cnpj
 *   Number, the CNPJ
 * @param $clean
 *   Boolean, FALSE to not clear the number
 * @return
 *   Boolean, true if its a valid CNPJ
 */
function _brazilianids_validate_cnpj(&$cnpj, $clean = TRUE) {
  // Clear the CPF
  if ($clean) {
    $cnpj = _brazilianids_clean_cpfcnpj($cnpj);
  }

  // Check if its not the forbidden combinations
  if (drupal_strlen($cnpj) != 14 or $cnpj == '00000000000000' or
      $cnpj == '11111111111111' or $cnpj == '22222222222222' or
      $cnpj == '33333333333333' or $cnpj == '44444444444444' or
      $cnpj == '55555555555555' or $cnpj == '66666666666666' or
      $cnpj == '77777777777777' or $cnpj == '88888888888888' or
      $cnpj == '99999999999999') {
    return NULL;
  }
  else {
    $i = 0;
    while ($i < 14) {
      $cnpj_d[$i] = drupal_substr($cnpj, $i, 1);
      $i++;
    }

    $digit = ($cnpj[0] * 5) + ($cnpj[1] * 4) + ($cnpj[2] * 3) + ($cnpj[3] * 2) +
      ($cnpj[4] * 9) + ($cnpj[5] * 8) + ($cnpj[6] * 7) + ($cnpj[7] * 6) +
      ($cnpj[8] * 5) + ($cnpj[9] * 4) + ($cnpj[10] * 3) + ($cnpj[11] * 2);

    // Calculate the digit and check it
    $digit = 11 - ($digit % 11);
    if ($digit == 10 or $digit == 11) {
      $digit = 0;
    }

    if ($digit != $cnpj{12}) {
      return NULL;
    }

    $digit = ($cnpj[0] * 6) + ($cnpj[1] * 5) + ($cnpj[2] * 4) +
      ($cnpj[3] * 3) + ($cnpj[4] * 2) + ($cnpj[5] * 9) + ($cnpj[6] * 8) +
      ($cnpj[7] * 7) + ($cnpj[8] * 6) + ($cnpj[9] * 5) + ($cnpj[10] * 4) +
      ($cnpj[11] * 3) + ($digit * 2);

    // Calculate the digit and check it
    $digit = 11 - ($digit % 11);
    if ($digit == 10 or $digit == 11) {
      $digit = 0;
    }

    if ($digit != $cnpj{13}) {
      return NULL;
    }

    return $cnpj;
  }
}

/**
 * Check if the provided CPF is valid
 *
 * @param &$cpf
 *   Number, the CPF number
 * @param $clean
 *   Boolean, FALSE to not clear the number
 * @return
 *   Boolean, true if its a valid CPF
 */
function _brazilianids_validate_cpf(&$cpf, $clean = TRUE) {
  // Clear the CPF
  if ($clean) {
    $cpf = _brazilianids_clean_cpfcnpj($cpf);
  }

  // Check if its not the forbidden combinations
  if (drupal_strlen($cpf) != 11 or $cpf == '00000000000' or
      $cpf == '11111111111' or $cpf == '22222222222' or
      $cpf == '33333333333' or $cpf == '44444444444' or
      $cpf == '55555555555' or $cpf == '66666666666' or
      $cpf == '77777777777' or $cpf == '88888888888' or
      $cpf == '99999999999') {
    return NULL;
  }

  // Check the 11st and 12nd numbers
  for ($numbers = 9; $numbers <= 10; $numbers++) {
    $digit = 0;
    for ($i = 0; $i < $numbers; $i++) {
      $digit += $cpf{$i} * ($numbers + 1 - $i);
    }

    // Calculate the digit and check it
    $digit = 11 - ($digit % 11);
    if ($digit == 10 or $digit == 11) {
      $digit = 0;
    }
    if ($digit != $cpf{$numbers}) {
      return NULL;
    }
  }

  return $cpf;
}

/**
 * Clean the string removing all characters except the digits
 * @param $cpfcnpj
 *   Original "dirty" cpfcnpf
 * @return 
 *   Returns the clean cpfcnpj
 */
function _brazilianids_clean_cpfcnpj($cpfcnpj) {
  return preg_replace('/[^0-9]/', '', $cpfcnpj);
}
